package com.zzyl.nursing.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zzyl.common.constant.CacheConstants;
import com.zzyl.common.exception.base.BaseException;
import com.zzyl.common.utils.StringUtils;
import com.zzyl.nursing.domain.AlertData;
import com.zzyl.nursing.domain.AlertRule;
import com.zzyl.nursing.domain.DeviceData;
import com.zzyl.nursing.mapper.AlertDataMapper;
import com.zzyl.nursing.mapper.DeviceMapper;
import com.zzyl.nursing.service.IAlertDataService;
import com.zzyl.nursing.service.IAlertRuleService;
import com.zzyl.system.mapper.SysUserRoleMapper;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 报警数据Service业务层处理
 * 
 * @author yjr
 * @date 2025-05-29
 */
@Slf4j
@Service
public class AlertDataServiceImpl extends ServiceImpl<AlertDataMapper, AlertData> implements IAlertDataService
{
    @Autowired
    private AlertDataMapper alertDataMapper;

    /**
     * 查询报警数据
     * 
     * @param id 报警数据主键
     * @return 报警数据
     */
    @Override
    public AlertData selectAlertDataById(Long id)
    {
        return getById(id);
    }

    /**
     * 查询报警数据列表
     * 
     * @param alertData 报警数据
     * @return 报警数据
     */
    @Override
    public List<AlertData> selectAlertDataList(AlertData alertData)
    {
        return alertDataMapper.selectAlertDataList(alertData);
    }

    /**
     * 新增报警数据
     * 
     * @param alertData 报警数据
     * @return 结果
     */
    @Override
    public int insertAlertData(AlertData alertData)
    {
        return save(alertData) ? 1 : 0;
    }

    /**
     * 修改报警数据
     * 
     * @param alertData 报警数据
     * @return 结果
     */
    @Override
    public int updateAlertData(AlertData alertData)
    {
        return updateById(alertData) ? 1 : 0;
    }

    /**
     * 批量删除报警数据
     * 
     * @param ids 需要删除的报警数据主键
     * @return 结果
     */
    @Override
    public int deleteAlertDataByIds(Long[] ids)
    {
        return removeByIds(Arrays.asList(ids)) ? 1 : 0;
    }

    /**
     * 删除报警数据信息
     * 
     * @param id 报警数据主键
     * @return 结果
     */
    @Override
    public int deleteAlertDataById(Long id)
    {
        return removeById(id) ? 1 : 0;
    }

    @Autowired
    private IAlertRuleService iAlertRuleService;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private DeviceMapper deviceMapper;
    @Autowired
    private SysUserRoleMapper sysUserRoleMapper;

    @Value("${alertRule.roleAdmin}")
    private String roleAdmin;

    @Value("${alertRule.roleRepair}")
    private String roleRepair;

    /**
     * 报警数据过滤
     */
    @Override
    public void alertFilter() {
        //查看所有规则
        Long count = iAlertRuleService.lambdaQuery().eq(AlertRule::getStatus, 1).count();
        if (count<=0){
            log.error("[报警数据过滤]报警规则为空,不处理");
            return;
        }

        //查看所有设备上报的数据
        List<Object> deviceAllDataListObj = redisTemplate.opsForHash().values(CacheConstants.IOT_DEVICE_LAST_DATA_KEY);
        if (CollUtil.isEmpty(deviceAllDataListObj)){
            log.error("[报警数据过滤]设备上报的数据为空,不处理");
            return;
        }

        //数据格式标准化处理
        List<DeviceData> deviceAllDataList=new ArrayList<>();
        for (Object deviceDataList : deviceAllDataListObj) {
            List<DeviceData> deviceData = JSONUtil.toList(deviceDataList.toString(), DeviceData.class);
            deviceAllDataList.addAll(deviceData);
        }

        //遍历所有设备上报数据
        for (DeviceData deviceData : deviceAllDataList) {
            //设置设备上报数据过期时间
            int limit = 6000;

            //检查设备上报数据是否过期
            long between = LocalDateTimeUtil.between(deviceData.getAlarmTime(), LocalDateTime.now(), ChronoUnit.SECONDS);
            if (between>limit){
                log.error("[报警数据过滤]设备上报的数据已过期,不处理");
                continue;
            }

            //获取报警规则
            List<AlertRule> alertRuleList = getAlertRuleList(deviceData);
            if (alertRuleList == null) continue;

            for (AlertRule alertRule : alertRuleList) {
                //判断生效时间是否合适
                if (checkValidTime(deviceData, alertRule)) continue;

                //判断数据是否达到阈值
                Double dataValue = Double.valueOf(deviceData.getDataValue());
                Double value = alertRule.getValue();
                String operator = alertRule.getOperator();
                int compare = NumberUtil.compare(dataValue, value);

                //设置报警数的redis key
                String countKey = CharSequenceUtil.format(CacheConstants.IOT_ALERT_COUNT_PREFIX, deviceData.getIotId(), deviceData.getFunctionId(), alertRule.getId());
                if (("<".equals(operator) && compare>=0) || (">=".equals(operator) && compare<0)){
                    redisTemplate.delete(countKey);
                    log.error("[报警数据过滤]数据未达到阈值,不处理");
                    continue;
                }

                //查询redis中沉默周期是否结束
                String silentKey = CharSequenceUtil.format(CacheConstants.IOT_ALERT_SILENT_PREFIX, deviceData.getIotId(), deviceData.getFunctionId(), alertRule.getId());
                if (StringUtils.isNotBlank(redisTemplate.opsForValue().get(silentKey))){
                    log.error("[报警数据过滤]沉默周期未结束,不处理");
                    continue;
                }

                //判断报警次数是否达到
                Long increment = redisTemplate.opsForValue().increment(countKey);
                if (increment<alertRule.getDuration()){
                    log.error("[报警数据过滤]报警次数未达到,不处理");
                    continue;
                }

                //满足条件删除redis报警数,添加redis沉默周期
                redisTemplate.delete(countKey);
                redisTemplate.opsForValue().setIfAbsent(silentKey, "123", alertRule.getAlertSilentPeriod()*60, TimeUnit.SECONDS);

                //获取负责员工的id
                List<Long> userIdList = getUserIdList(deviceData, alertRule);

                //整理数据上报
                saveBatchAlertData(deviceData, alertRule, userIdList);

            }
        }

    }

    /**
     * 判断生效时间是否合适
     * @param deviceData
     * @param alertRule
     * @return
     */
    private static boolean checkValidTime(DeviceData deviceData, AlertRule alertRule) {
        //判断规则是否在生效时间内
        String alertEffectivePeriod = alertRule.getAlertEffectivePeriod();
        String[] split = alertEffectivePeriod.split("~");
        LocalTime beginTime = LocalTime.parse(split[0]);
        LocalTime endTime = LocalTime.parse(split[1]);
        LocalTime localTime = deviceData.getAlarmTime().toLocalTime();
        if (localTime.isBefore(beginTime) || localTime.isAfter(endTime)){
            log.error("[报警数据过滤]规则不在生效时间内,不处理");
            return true;
        }
        return false;
    }

    /**
     * 获取报警规则
     * @param deviceData
     * @return
     */
    private @Nullable List<AlertRule> getAlertRuleList(DeviceData deviceData) {
        //查询设备对应规则数据
        List<AlertRule> alertRules = iAlertRuleService.lambdaQuery()
                .eq(AlertRule::getProductKey, deviceData.getProductKey())
                .eq(AlertRule::getFunctionId, deviceData.getFunctionId())
                .eq(AlertRule::getStatus, 1)
                .in(AlertRule::getIotId, -1, deviceData.getIotId())
                .list();
        //去重
        List<AlertRule> alertRuleList = alertRules.stream().distinct().collect(Collectors.toList());

        //判断设备对应规则数据是否为空
        if (CollUtil.isEmpty(alertRuleList)){
            log.error("[报警数据过滤]设备对应规则数据为空,不处理");
            return null;
        }
        return alertRuleList;
    }

    /**
     * 获取该报警设备负责的员工
     * @param deviceData
     * @param alertRule
     * @return
     */
    private @NotNull List<Long> getUserIdList(DeviceData deviceData, AlertRule alertRule) {
        //判断是否是老人数据
        List<Long> userIds = null;
        if (alertRule.getAlertDataType()==0){
            //判断是移动设备还是固定设备
            if (deviceData.getLocationType()==0){
                //移动设备根据iotId查询负责的员工
                 userIds = deviceMapper.selectNursingIdsByMoveIotId(deviceData.getIotId());

            }else {
                //固定设备根据床位查询负责的员工
                userIds = deviceMapper.selectNursingIdsByFixedIotId(deviceData.getIotId());

            }

        }else {
            //设备异常数据,通过维修工角色名查询负责员工
            userIds= sysUserRoleMapper.selectUserIdByRoleName(roleRepair);

        }
        //获取管理员id
        List<Long> adminIds = sysUserRoleMapper.selectUserIdByRoleName(roleAdmin);
        userIds.addAll(adminIds);
        List<Long> userIdList = userIds.stream().distinct().collect(Collectors.toList());
        return userIdList;
    }


    /**
     * 整理数据批量上传报警数据
     * @param deviceData
     * @param alertRule
     * @param userIdList
     */
    private void saveBatchAlertData(DeviceData deviceData, AlertRule alertRule, List<Long> userIdList) {
        //整理数据上报
        AlertData alertData =new AlertData();
        BeanUtils.copyProperties(deviceData, alertData);
        alertData.setId(null);
        alertData.setType(alertRule.getAlertDataType());
        alertData.setAlertRuleId(alertRule.getId());
        alertData.setStatus(0);
        String reasonTemplate = "功能{}{}{}，持续了{}个周期才报警，沉默周期：{}";
        String alertReason = CharSequenceUtil.format(reasonTemplate,
                alertRule.getFunctionId(),
                alertRule.getOperator(),
                alertRule.getValue(),
                alertRule.getDuration(),
                alertRule.getAlertSilentPeriod()
        );
        alertData.setAlertReason(alertReason);

        //变量员工id给每个员工发送报警
        List<AlertData> alertDataList = new ArrayList<>();
        for (Long userId : userIdList) {
            AlertData userAlertData =new AlertData();
            BeanUtils.copyProperties(alertData, userAlertData);
            userAlertData.setUserId(userId);
            alertDataList.add(userAlertData);
        }

        //批量添加报警数据
        boolean saveBatch = this.saveBatch(alertDataList);
        if (!saveBatch){
            throw new BaseException("保存用户保存数据失败");
        }
    }
}
